package cn.tworice.common.util;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 具有时效性的HashMap
 * 可以设置具有时效的键值对
 * 2022年9月18日 更新 适配JDK8
 *
 * @author 二饭
 * @version 1.0
 */
public class AgingMap<K, V> implements Serializable {

    private static final long serialVersionUID = 2756845907061754852L;

    /**
     * 默认最大长度
     */
    private int maxLength = 10;

    /**
     * 用于存储数据的HashMap集合
     */
    private transient HashMap<K, V> map = null;

    private transient HashMap<K, Timer> timerMap = null;

    /**
     * 用于初始化AgingMap
     * 初始化用于存储数据的HashMap
     * 初始化用于设置时效的Timer
     * @author 二饭
     */
    public AgingMap() {
        map = new HashMap<>();
        timerMap = new HashMap<>();
    }

    public AgingMap(Integer maxLength) {
        this.maxLength = maxLength;
        map = new HashMap<>();
        timerMap = new HashMap<>();
    }

    /**
     * 添加长期有效的键值对
     *
     * @param key   Map集合的键
     * @param value Map集合的值
     * @return V 返回存储成功后的值
     * @author 二饭
     */
    public V put(K key, V value) {
        return map.put(key, value);
    }

    /**
     * 添加有时效的键值对
     *
     * @param key   Map集合的键
     * @param value Map集合的值
     * @param ms    该键值对的时效
     * @return V 返回存储成功后的值
     * @author 二饭
     */
    public V put(K key, V value, long ms) {
        if (refuse()) {
            put(key, value);
            aging(key, ms);
            return value;
        } else {
            return null;
        }
    }


    /**
     * 设置时效结束后删除相应Key
     *
     * @param key Map集合的键
     * @param ms  规定该Map集合键值对的时效
     * @author 二饭
     */
    public void aging(final K key, long ms) {
        final Timer timer = new Timer();
        timerMap.put(key, timer);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                map.remove(key);
                timer.cancel();
                timer.purge();
                timerMap.remove(key);
            }
        }, ms);
    }

    /**
     * 删除指定的Key
     * 清除指定的Timer
     *
     * @param key Map集合的键
     * @return V 返回删除的Map集合的值
     * @author 二饭
     */
    public V remove(K key) {
        if (timerMap.containsKey(key)) {
            timerMap.get(key).cancel();
            timerMap.get(key).purge();
            timerMap.remove(key);
        }
        return map.remove(key);
    }

    /**
     * 通过键值获取值
     *
     * @param key Map的键
     * @return V 返回Map集合存储的值
     * @author 二饭
     */
    public V get(K key) {
        return map.get(key);
    }

    /**
     * 判断是否存在该键值对
     *
     * @param key   Map集合的键
     * @param value Map集合的值
     * @author 二饭
     */
    public boolean exist(K key, V value) {
        return map.containsKey(key) && map.get(key).equals(value);
    }


    /**
     * 拒绝策略
     * 当到达最高容积后拒绝再添加元素
     *
     * @return boolean
     * @author 二饭
     */
    private boolean refuse() {
        return timerMap.size() < maxLength;
    }

    /**
     * 获取数据Map
     *
     * @return Map<K, V>
     */
    public Map<K, V> getMap() {
        return this.map;
    }

    /**
     * 判断key是否存在
     *
     * @param key 数据Map的key
     * @return 返回是否存在
     */
    public boolean containsKey(K key) {
        return map.containsKey(key);
    }

    /**
     * 如果存在则删除Key
     *
     * @param key 数据Map的key
     */
    public void removeKey(K key) {
        this.remove(key);
    }


}
